/**
 * \brief   Linux系统和Windows系统公共常用接口
*/
#include "common_interface.h"
#include "common_errno.h"
#include "internal_common.h"
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define COMMON_SIZE_UINT32_T    4   //范围
#define COMMON_PATH_MAX         256 //路径最大长度

// 内部布尔类型
typedef enum {
    COMMON_BOOL_FALSE,
    COMMON_BOOL_TRUE,
    COMMON_BOOL_MAX,
}common_bool;

// 数字正负性
typedef enum {
    COMMON_OPERATE_NEGATIVE,
    COMMON_OPERATE_POSITIVE,
    COMMON_OPERATE_MAX,
}common_operate;

// 数字大小比较
typedef enum {
    COMMON_COMPARE_BIGGER,
    COMMON_COMPARE_SMALLER,
    COMMON_COMPARE_EQUAL,
    COMMON_COMPARE_MAX,
}common_compare;

/**
 * 判断大小端
*/
int common_get_system_endian(common_endian *result)
{
    union common_union {
        uint32_t number;
        char arr[COMMON_SIZE_UINT32_T];
    };

    union common_union temp;
    temp.number = 0x01020304;
    if(temp.arr[0] == 0x01) {
        *result = COMMON_BIG_ENDIAN;
    }
    else {
        *result = COMMON_SMALL_ENDIAN;
    }

    return COM_OK;
}

/**
 * 判断路径是否合法
*/
int common_judge_path(const char *path, int path_len)
{
    int len = 0;    //路径长度
    int i;
    if(path == NULL) {
        return COM_BAD_INPUT;
    }
    if(path_len <= 0) {
        for(i = 0; i < COMMON_PATH_MAX; i++) {  //检测路径长度是否小于256
            if(path[i] == '\0') {
                len = i;
                break;
            }
        }
        if(len == 0 && path[COMMON_PATH_MAX] == '\0') {
            len = COMMON_PATH_MAX;
        }
    }
    else {
        len = path_len;
    }

    if(path_len > COMMON_PATH_MAX) {
        return COM_ERR_LENGTH;
    }

    if(access(path, F_OK) == 0) {
        return COM_OK;
    }
    else {
        return COM_ERR_FILE_NOT_EXISTS;
    }
}

/**
 * 快速排序函数
*/
void quick_sort_function(int *arr, int left, int right){
    if(left == right && right - left == 1 && left >= right) {
        return ;
    }
	int l = 0;
	int r = right;
	int key = arr[left];
	while(l < r){
		while(l < r && key <= arr[r]){
			r--;
		}
		arr[l] = arr[r];
		arr[r] = key;
		while(l < r && key >= arr[l]){
			l++;
		}
		arr[r] = arr[l];
		arr[l] = key;
	}
	quick_sort_function(arr, left, l-1);
	quick_sort_function(arr, l+1, right);
}

/**
 * 调用快速排序，返回对应信息
*/
int quick_sort(int *arr, int left, int right){
	if(arr == NULL) {
        return COM_BAD_INPUT;
    }
    if(left >= right){
		return COM_BAD_INPUT;
	}
    quick_sort_function(arr,left,right);
    return COM_OK;
}

static uint64_t internal_byte_common_trans(uint64_t number, common_byte_type byte_type, int position) {
    uint64_t mask = 1 << position;
    if(((number & mask) == 0 && byte_type == COMMON_BYTE_ONE) || ((number & mask) != 0 && byte_type == COMMON_BYTE_ZERO)) {
        number ^= mask;
    }
    return number;
}

static common_byte_type internal_byte_to_type(uint64_t number, int position) {
    return (common_byte_type)((number >> position) & 1) ;
}

int common_byte_1_set(uint8_t *in, common_byte_type byte_type, int position) {
    if(in == NULL || (byte_type != COMMON_BYTE_ZERO && byte_type != COMMON_BYTE_ONE) || position < 0 || position > 7) {
        return COM_BAD_INPUT;
    }

    *in = (uint8_t)internal_byte_common_trans((uint64_t)*in, byte_type, position);

    return COM_OK;
}

int common_byte_1_get(uint8_t *in, common_byte_type *byte_type, int position) {
    if(in == NULL || byte_type == NULL || position < 0 || position > 7) {
        return COM_BAD_INPUT;
    }

    *byte_type = internal_byte_to_type((uint64_t)*in, position);
    
    return COM_OK;
}

int common_byte_2_set(uint16_t *in, common_byte_type byte_type, int position) {
    if(in == NULL || (byte_type != COMMON_BYTE_ZERO && byte_type != COMMON_BYTE_ONE) || position < 0 || position > 15) {
        return COM_BAD_INPUT;
    }

    *in = (uint16_t)internal_byte_common_trans((uint64_t)*in, byte_type, position);

    return COM_OK;
}

int common_byte_2_get(uint16_t *in, common_byte_type *byte_type, int position) {
    if(in == NULL || byte_type == NULL || position < 0 || position > 15) {
        return COM_BAD_INPUT;
    }

    *byte_type = internal_byte_to_type((uint64_t)*in, position);
    
    return COM_OK;
}

int common_byte_4_set(uint32_t *in, common_byte_type byte_type, int position) {
    if(in == NULL || (byte_type != COMMON_BYTE_ZERO && byte_type != COMMON_BYTE_ONE) || position < 0 || position > 31) {
        return COM_BAD_INPUT;
    }

    *in = (uint32_t)internal_byte_common_trans((uint64_t)*in, byte_type, position);

    return COM_OK;
}

int common_byte_4_get(uint32_t *in, common_byte_type *byte_type, int position) {
    if(in == NULL || byte_type == NULL || position < 0 || position > 31) {
        return COM_BAD_INPUT;
    }

    *byte_type = internal_byte_to_type((uint64_t)*in, position);
    
    return COM_OK;
}

int common_byte_8_set(uint64_t *in, common_byte_type byte_type, int position) {
    if(in == NULL || (byte_type != COMMON_BYTE_ZERO && byte_type != COMMON_BYTE_ONE) || position < 0 || position > 63) {
        return COM_BAD_INPUT;
    }

    *in = (uint64_t)internal_byte_common_trans((uint64_t)*in, byte_type, position);

    return COM_OK;
}

int common_byte_8_get(uint64_t *in, common_byte_type *byte_type, int position) {
    if(in == NULL || byte_type == NULL || position < 0 || position > 63) {
        return COM_BAD_INPUT;
    }

    *byte_type = internal_byte_to_type((uint64_t)*in, position);
    
    return COM_OK;
}

// 检查一个输入大数是否为合法数字
static int internal_check_str_is_number(const char number[]) {
    int length = strlen(number);
    int i = 0;
    for(i = 0; i < length; i++) {
        if(!((number[i] >= '0' && number[i] <= '9') || (number[i] == '-' || number[i] == '+'))) {
            return 0;
        }
    }
    return 1;
}

// 内部加法算法，左加右，不考虑符号
static int internal_plus(char *out, int *olen, int osize, const char left[], int length_left, const char right[], int length_right) {
    int *result = NULL;
    int result_size = length_left > length_right ? length_left + 1 : length_right + 1;
    int result_count = 0;
    int ret = COM_OK;

    int left_number = 0;
    int right_number = 0;
    int l = 0, r = 0;

    int i;

    int temp = 0;

    result = (int *)malloc(sizeof(int) * result_size);
    if(result == NULL) {
        ret = COM_MEM_LESS;
        goto exit;
    }
    memset(result, 0, sizeof(int) * result_size);

    l = length_left - 1;
    r = length_right - 1;
    result_count = 0;

    // 赋值给int数组
    while(result_count < result_size && (l >= 0 || r >= 0)) {
        left_number = 0;
        right_number = 0;
        // 拿到数字
        if(l >= 0) {
            left_number = left[l] - '0';
            l--;
        }
        if(r >= 0) {
            right_number = right[r] - '0';
            r--;
        }
        result[result_count] = left_number + right_number;
        result_count++;
    }

    // 从前向后进行进位操作
    for(i = 0; i < result_count && i < result_size; i++) {
        if(result[i] >= 10) {
            result[i + 1] += result[i] / 10;
            result[i] %= 10;
            if(i == result_count - 1) {
                result_count++;
            }
        }
    }

    // 从后向前赋值给out数组
    temp = 0;
    for(i = result_count - 1; i >= 0 && temp < result_size; i--) {
        out[temp] = result[i] + '0';
        temp++;
    }
    *olen = temp;

exit:
    if(result != NULL) {
        free(result);
    }
    return ret;

}

// 内部减法算法，左减右，不考虑符号，左操作数一定是大于右操作数
static int internal_subtraction(char *out, int *olen, int osize, const char left[], int left_size, const char right[], int right_size) {
    int ret = COM_OK;
    int *result = NULL;
    int result_count = 0;
    int result_size = left_size > right_size ? left_size : right_size;

    int i = 0;
    int temp = 0;

    int l = 0, r = 0;
    int number_left = 0, number_right = 0;

    result = (int *)malloc(sizeof(int) * result_size);
    if(result == NULL) {
        ret = COM_MEM_LESS;
        goto exit;
    }
    memset(result, 0, sizeof(int) * result_size);
    internal_debug("result init ok\n");

    // 将两个操作数，直接left - right存放到result中，尽管会有负数，但是后面能够统一处理
    result_count = 0;
    l = left_size - 1;
    r = right_size - 1;
    while(result_count < result_size && (l >= 0 || r >= 0)) {
        number_left = 0;
        number_right = 0;
        if(l >= 0) {
            number_left = left[l] - '0';
            l--;
        }
        if(r >= 0) {
            number_right = right[r] - '0';
            r--;
        }
        result[result_count] = number_left - number_right;
        result_count++;
    }

    // 一次遍历，消除掉所有的借位情况
    for(i = 0; i < result_count; i++) {
        if(result[i] < 0) {
            result[i] += 10;
            result[i + 1] --;
            if(i == result_count - 1 && result[i + 1] == 0) {
                result_count--;
            }
        }
        internal_debug("%d\n", result[i]);
    }

    // 一次遍历，复制到out中
    temp = 0;
    for(i = result_count - 1; i >= 0 && temp < osize; i--) {
        out[temp] = result[i] + '0';
        temp++;
    }
    *olen = temp;
    internal_debug("%d\n", temp);
    ret = COM_OK;

exit:
    if(result != NULL) {
        free(result);
    }
    return ret;
}

// 比较两个大数的大小，bigger代表number1大，smaller代表number2大，equal代表两者相等
static common_compare internal_compare(const char number1[], const char number2[]) {
    const char *head_number1 = NULL;
    const char *head_number2 = NULL;

    int length_number1 = 0;
    int length_number2 = 0;

    int i = 0;

    int temp = 0;
    while(!(number1[temp] >= '0' && number1[temp] <= '9')) {
        temp++;
    }
    head_number1 = number1 + temp;

    temp = 0;
    while(!(number2[temp] >= '0' && number2[temp] <= '9')) {
        temp++;
    }
    head_number2 = number2 + temp;

    length_number1 = strlen(head_number1);
    length_number2 = strlen(head_number2);

    if(length_number1 > length_number2) {
        return COMMON_COMPARE_BIGGER;
    }
    if(length_number1 < length_number2) {
        return COMMON_COMPARE_SMALLER;
    }

    for(i = 0; i < length_number1; i++) {
        if(head_number1[i] > head_number2[i]) {
            return COMMON_COMPARE_BIGGER;
        }
        else if(head_number1[i] < head_number2[i]) {
            return COMMON_COMPARE_SMALLER;
        }
    }

    return COMMON_COMPARE_EQUAL;
}

// 去除前导零
static void internal_clear_front_zero(char input[], int *olen) {
    int length = *olen;
    int counter = 0;
    int i = 0;
    while(input[i] == '0') {
        i++;
    }
    for(; i < length; i++) {
        input[counter] = input[i];
        counter++;
    }
    *olen = counter;
}

// 获得符号
common_operate internal_get_operate(const char number[]) {
    if(number[0] == '-') {
        return COMMON_OPERATE_NEGATIVE;
    }
    return COMMON_OPERATE_POSITIVE;
}

/**
 * 大数加法算法（带符号数字）：
1. 输入判断
2. 判断输入符号是否同号，同号视为相加，异号视为相减，使用common_bool is_same，true为同号，false为异号
    2.1. 同号状态下，直接使用int走一遍即可，从后向前
        2.1.1. 如果都是负号，则输出结果头带上负号
        2.1.2. 修正完符号后进行加法计算
    2.2. 异号状态下，视为减法运算
        2.2.1. 如果左操作数为负号
            2.2.1.1. 如果左操作数比右操作数大，调用公共减接口，结束后将结果赋值-号，结果为负数
            2.2.1.2. 如果右操作数比左操作数大，调用公共减接口时需要调换顺序，结束后无需赋值符号，结果为正数
        2.2.2. 如果右操作数为负号
            2.2.2.1. 如果左操作数比右操作数大，调用公共减接口，结束后无需赋值符号，结果为正数
            2.2.2.2. 如果右操作数比左操作数大，调用公共减接口时需要调换顺序，结束后赋值-号，结果为负数

*/
int common_big_number_plus(char *out, int *olen, int out_size, const char left[], const char right[]) {
    int length_left = 0, length_right = 0;  // 左右运算数长度
    int ret = COM_BAD_INPUT;

    const char *head_left = NULL;
    const char *head_right = NULL;
    int temp = 0;

    // 运算符
    common_operate operate_left = COMMON_OPERATE_MAX, operate_right = COMMON_OPERATE_MAX;
    // 是否为同号
    common_bool is_same_operate = COMMON_BOOL_FALSE;
    // 谁大谁小
    common_compare compare = COMMON_COMPARE_MAX;

    // step 1 输入判断
    if(out == NULL || olen == NULL || left == NULL || right == NULL) {  // 输入检测
        return COM_BAD_INPUT;
    }

    if((!internal_check_str_is_number(left)) || (!internal_check_str_is_number(right))) { // 数字是否合法检测
        return COM_BIG_NUMBER_NOT_NUMBER;
    }

    length_left = strlen(left);
    length_right = strlen(right);

    if(out_size < length_left || out_size < length_right) { // buffer太小，无法装下运算结果
        return COM_BIG_NUMBER_OUT_BUF_SMALL;
    }

    // step 2 判断符号是否相同
    // 拿到符号
    operate_left = internal_get_operate(left);
    operate_right = internal_get_operate(right);

    // 判断符号是否相同
    if(operate_left == operate_right) {
        is_same_operate = COMMON_BOOL_TRUE;
    }
    else {
        is_same_operate = COMMON_BOOL_FALSE;
    }
    
    // step 2.1 同号视为相加
    if(is_same_operate == COMMON_BOOL_TRUE) {
        if(operate_left == COMMON_OPERATE_NEGATIVE) {
            internal_debug("operate is negative\n");
            ret = internal_plus(out + 1, olen, out_size - 1, left + 1, length_left - 1, right + 1, length_right - 1);
            out[0] = '-';
            *olen = (*olen) + 1;
        }
        else {
            internal_debug("operate is positive\n");
            ret = internal_plus(out, olen, out_size, left, length_left, right, length_right);
        }
        goto exit;
    }
    // step 2.2 不同符号
    else {
        internal_debug("start to compare\n");
        // 比较大小
        compare = internal_compare(left, right);
        internal_debug("compare is %d\n", compare);
        if(compare == COMMON_COMPARE_EQUAL) {
            internal_debug("equal\n");
            out[0] = '0';
            *olen = 1;
            ret = COM_OK;
            goto exit;
        }
        internal_debug("compare ok\n");

        // 过滤掉符号的影响
        temp = 0;
        while(!(left[temp] >= '0' && left[temp] <= '9')) {
            temp++;
        }
        head_left = left + temp;
        length_left -= temp;
        internal_debug("temp = %d\n", temp);
    
        temp = 0;
        while(!(right[temp] >= '0' && right[temp] <= '9')) {
            temp++;
        }
        head_right = right + temp;
        length_right -= temp;
        internal_debug("temp = %d\n", temp);
        

        // step 2.2.1 左操作数为负数
        if(operate_left == COMMON_OPERATE_NEGATIVE) {
            // step 2.2.1.1 左操作数比右操作数大
            if(compare == COMMON_COMPARE_BIGGER) {
                internal_debug("step 2.2.1.1\n");
                out[0] = '-';
                ret = internal_subtraction(out + 1, olen, out_size - 1, head_left, length_left, head_right, length_right);
                *olen = (*olen) + 1;
                goto exit;
            }
            // step 2.2.1.2 右操作数比左操作数大
            else {
                internal_debug("step 2.2.1.2\n");
                ret = internal_subtraction(out, olen, out_size, head_right, length_right, head_left, length_left);
                goto exit;
            }
        }
        // step 2.2.2 右操作数为负数
        else if(operate_right == COMMON_OPERATE_NEGATIVE) {
            // step 2.2.2.1 左操作数比右操作数大
            if(compare == COMMON_COMPARE_BIGGER) {
                internal_debug("step 2.2.2.1\n");
                ret = internal_subtraction(out, olen, out_size, head_left, length_left, head_right, length_right);
                goto exit;
            }
            // step 2.2.2.2 右操作数比左操作数大
            else {
                internal_debug("step 2.2.2.2\n");
                out[0] = '-';
                ret = internal_subtraction(out + 1, olen, out_size - 1, head_right, length_right, head_left, length_left);
                *olen = (*olen) + 1;
                goto exit;
            }
        }
    }

exit:
    internal_clear_front_zero(out, olen);
    return ret;

}

/**
 * 大数减法算法思想：
 * 1. 左操作数取反，调用大数加法即可
*/
int common_big_number_subtraction(char *out, int *olen, int out_size, const char left[], const char right[]) {
    int length = 0;
    int i = 0;
    int ret = 0;

    if(right == NULL) {
        return COM_BAD_INPUT;
    }

    length = strlen(right);

    if(length <= 0) {
        return COM_BAD_INPUT;
    }

    char *temp = (char *)malloc(sizeof(char) * (length + 5));

    memset(temp, 0, length + 5);

    if(right[0] == '-') {
        for(i = 1; i < length; i++) {
            temp[i - 1] = right[i];
        }
    }
    else {
        temp[0] = '-';
        for(i = 0; i < length; i++) {
            temp[i + 1] = right[i];
        }
    }

    ret = common_big_number_plus(out, olen, out_size, left, temp);

    free(temp);
    return ret;
}

/**
 * 大数乘法算法思想：
 * 1. out_size >= (strlen(left) > strlen(right) ? strlen(left) : strlen(right)) * 2 ? 进行下一步 : return COM_BIG_NUMBER_OUT_BUF_SMALL
 * 2. 判断结果的正负性
 * 3. 开始按位进行乘法运算，要记住偏移位数，直接存放到out中
 * 4. 将数字转换成字符串
 * 5. 处理前导零
 * 6. 赋值olen
 */
int common_big_number_multiplication(char *out, int *olen, int out_size, const char left[], const char right[]) {
    int length_left = 0, length_right = 0;
    int i = 0, j = 0;
    // 正负性，0是负数，1是正数
    common_operate is_positive = COMMON_OPERATE_MAX;
    // 输出数组base
    int out_base = 0;
    // 中间结果
    int64_t *temp = NULL;
    int ret = COM_BAD_INPUT;

    // 过滤掉符号位的指针
    const char *head_left = NULL, *head_right = NULL;

    if(out == NULL || olen == NULL || left == NULL || right == NULL) {  // 输入检测
        return COM_BAD_INPUT;
    }

    if(!internal_check_str_is_number(left) || !internal_check_str_is_number(right)) { // 数字是否合法检测
        return COM_BIG_NUMBER_NOT_NUMBER;
    }

    length_left = strlen(left);
    length_right = strlen(right);

    // step1: 判断buffer
    if(out_size < length_left * 2 || out_size < length_right * 2) { // buffer太小
        return COM_BIG_NUMBER_OUT_BUF_SMALL;
    }

    // step2: 判断正负性
    if((left[0] != '-' && right[0] != '-') || (left[0] == '-' && left[0] == '-')) {
        is_positive = COMMON_OPERATE_POSITIVE;
    }
    else {
        is_positive = COMMON_OPERATE_NEGATIVE;
    }

    // 过滤掉符号
    i = 0;
    while(left[i] < '0' || left[i] > '9') {
        i++;
    }
    head_left = left + i;
    length_left -= i;

    i = 0;
    while(right[i] < '0' || right[i] > '9') {
        i++;
    }
    head_right = right + i;
    length_right -= i;

    // 申请内存
    temp = (int64_t *)malloc(sizeof(int64_t) * out_size);
    if(temp == NULL) {
        ret = COM_MEM_LESS;
        goto exit;
    }
    memset(temp, 0, sizeof(int64_t) * out_size);
    // 赋值base
    out_base = 0;

    // step3: 按位进行乘法运算
    for(i = length_left - 1; i >= 0; i--) {
        for(j = length_right - 1; j >= 0; j--) {
            temp[out_base + length_right - 1 - j] += (head_left[i] - '0') *  (head_right[j] - '0');
        }
        out_base++;
    }
    out_base += length_right - 1;

    // step4: 处理数字进位
    for(i = 0; i < out_base; i++) {
        if(temp[i] >= 10) {
            temp[i + 1] += temp[i] / 10;
            temp[i] = temp[i] % 10;
            if(i == out_base - 1) {
                out_base++;
            }
        }
    }

    // step5: 复制到结果中
    i = 0;
    if(is_positive == COMMON_OPERATE_NEGATIVE) {
        out[0] = '-';
        i = 1;
    }

    for(j = 0; j < out_base; j++) {
        internal_debug("%d\n", temp[j]);
    }

    for(j = 0; j < out_base; j++) {
        out[i] = temp[out_base - 1 - j] + '0';
        i++;
    }

    *olen = i;

    ret = COM_OK;

exit:
    free(temp);

    return ret;
}